﻿#include "dispatchwidget.h"
#include <QDragEnterEvent>
#include <QGridLayout>
#include <QMimeData>
#include <QPushButton>
#include <QToolTip>
#include "channelinfo.h"
#include "clientcallback.h"
#include "globaltools.h"
#include "servertimesync.h"
#include "dispatchvideo.h"

DispatchWidget::DispatchWidget(QWidget *parent) : QWidget(parent), isTalkingTo(0)
{
    connect(this, &DispatchWidget::drop, this, &DispatchWidget::drop_received, Qt::QueuedConnection);
    grid = new QGridLayout(this);
    setLayout(grid);
    setGrid(2, 3);
    ClientCallback::instance()->set_microphone_mute(P2PChanneInfo::p2pchannel_room_id, false);
}

DispatchWidget::~DispatchWidget()
{
    //全部发送关闭请求
    for (auto it = videoMap.constBegin(); it != videoMap.constEnd(); it++)
        ClientCallback::instance()->im_send_msg(it.key(), QString(), msg_type_dispatch_req_end, QString());
}

void DispatchWidget::handle_im_msg(int type, qint64 user_id, const QVariantHash &msg)
{
    if(type == msg_type_dispatch_start)
    {
        auto widget = videoMap.value(user_id, Q_NULLPTR);
        if(qobject_cast<DispatchVideo*>(widget))
        {
            //已经有了
            return;
        }
        else if (widget) {
            auto video = new DispatchVideo(this);
            video->uid = user_id;
            video->uname = widget->whatsThis();
            auto item = grid->replaceWidget(widget, video, Qt::FindDirectChildrenOnly);
            if(item)
            {
                widget->hide();
                widget->deleteLater();
                delete item;
                connect(video, &DispatchVideo::close_video, this, &DispatchWidget::close_video);
                videoMap[user_id] = video;
            }
            else
                delete video;
        }
    }
    else if (type == msg_type_dispatch_end) {
        closeVideo(user_id, QObject::trECSUTF8("%1停止分享视频"));
    }
    else if (type == msg_type_dispatch_reject) {
        closeVideo(user_id, QObject::trECSUTF8("%1正在忙，无法分享视频"));
    }
}

void DispatchWidget::handle_remote_video(qint64 user_id, const QPixmap &pix)
{
    if(auto video = qobject_cast<DispatchVideo*>(videoMap.value(user_id, Q_NULLPTR)))
        video->handleVideo(pix);
}

void DispatchWidget::handle_audio_volume(qint64 user_id, int volume)
{
    if(auto video = qobject_cast<DispatchVideo*>(videoMap.value(user_id, Q_NULLPTR)))
        video->handle_volume(volume);
}

bool DispatchWidget::eventFilter(QObject *watched, QEvent *event)
{
    auto type = event->type();
    if(type == QEvent::DragEnter)
    {
        if(auto e = reinterpret_cast<QDragEnterEvent *>(event))
        {
            if(e->proposedAction() == Qt::CopyAction && e->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
            {
                e->acceptProposedAction();
                return true;
            }
        }
    }
    else if(type == QEvent::Drop)
    {
        if(auto e = reinterpret_cast<QDropEvent*>(event))
        {
            emit drop(e->mimeData()->data("application/x-qabstractitemmodeldatalist"), watched);
            e->acceptProposedAction();
            return true;
        }
    }
    return false;
}

void DispatchWidget::slot_video_button_clicked()
{
    if(auto button = qobject_cast<QAbstractButton*>(sender()))
    {
        if(auto key = videoMap.key(button, 0)) {
            //取消等待
            button->setIcon(QIcon());
            button->setText(QLatin1String("+"));
            button->setWhatsThis(QString());
            videoMap.remove(key);
            //发送关闭请求
            ClientCallback::instance()->im_send_msg(key, QString(), msg_type_dispatch_req_end, QString());
        }
        else {
            emit showContact();
            showTooltip(QObject::trECSUTF8("请将调度对象从通讯录中拖到此窗口"), button);
        }
    }
}

void DispatchWidget::close_video(qint64 uid)
{
    closeVideo(uid, QString());
    //发送关闭请求
    ClientCallback::instance()->im_send_msg(uid, QString(), msg_type_dispatch_req_end, QString());
}

void DispatchWidget::drop_received(QByteArray encoded, QObject *watched)
{
    QDataStream stream(&encoded, QIODevice::ReadOnly);
    if (!stream.atEnd()) {
        int r, c;
        QMap<int, QVariant> v;
        stream >> r >> c >> v;
        addP2P(v, qobject_cast<QAbstractButton*>(watched));
    }
}

void DispatchWidget::setGrid(int row, int column)
{
    if(row == grid->rowCount() && column == grid->columnCount())
        return; //不变
    QList<QLayoutItem*> oldItems;
    while (grid->count() > 0) {
        if(auto item = grid->takeAt(0))
            oldItems.append(item);
    }
    setSizeIncrement(column, row);
    for (int i = 0; i < row; i ++)
    {
        grid->setRowStretch(i, 1);
        for (int j = 0; j < column; j++)
        {
            if(i == 0)
                grid->setColumnStretch(j, 1);
            if(oldItems.isEmpty())
            {
                //新建一个
                grid->addWidget(newButton(), i, j);
            }
            else
                grid->addItem(oldItems.takeFirst(), i, j);
        }
    }
    qDeleteAll(oldItems);
}

void DispatchWidget::addP2P(const QMap<int, QVariant> &v, QAbstractButton *button)
{
    qint64 uid = v.value(Qt::UserRole).toLongLong();
    if(!button || uid == ClientCallback::instance()->get_my_id())  //应该不会发生，但是以防万一
        return;
    if(videoMap.contains(uid))
    {
        showTooltip(QObject::trECSUTF8("已在调度列表中"), button);
        return;
    }
    videoMap[uid] = button;
    button->setIcon(v.value(Qt::DecorationRole).value<QPixmap>());
    button->setWhatsThis(v.value(Qt::DisplayRole).toString());
    button->setText(QObject::trECSUTF8("正在连接:%1\n点击取消").arg(button->whatsThis()));
    //发送调度请求
    ClientCallback::instance()->im_send_msg(uid, QString(), msg_type_dispatch_req, QString());
}

void DispatchWidget::closeVideo(qint64 user_id, const QString &tooltipFormat)
{
    auto it = videoMap.find(user_id);
    if(it != videoMap.end())
    {
        QString name;
        QWidget *childWidget = Q_NULLPTR;
        if(auto window = qobject_cast<DispatchVideo*>(*it))
        {
            name = window->uname;
            //新建一个
            auto newItem = newButton();
            auto item = grid->replaceWidget(window, newItem, Qt::FindDirectChildrenOnly);
            if(item)
            {
                window->hide();
                window->deleteLater();
                delete item;
                childWidget = newItem;
                if(isTalkingTo == user_id)
                {
                    ClientCallback::instance()->im_send_msg(user_id, QString(), msg_type_notify, P2PChanneInfo::end_talk);
                    ClientCallback::instance()->free_p2p_channel();
                    isTalkingTo = 0;
                }
            }
            else
                delete newItem;
        }
        else if(auto button = qobject_cast<QAbstractButton*>(*it))
        {
            button->setIcon(QIcon());
            button->setText(("+"));
            name = button->whatsThis();
            if(!name.isEmpty())
            {
                button->setWhatsThis(QString());
                childWidget = button;
            }
        }
        videoMap.erase(it);
        if(childWidget && !tooltipFormat.isEmpty())
            showTooltip(tooltipFormat.arg(name), childWidget);
    }
}

void DispatchWidget::showTooltip(const QString &text, QWidget *childWidget)
{
    auto fm = fontMetrics();
    auto rect = fm.boundingRect(text);
    rect.adjust(0, 0, 2, 2);
    auto childRect = childWidget->geometry();
    rect.moveCenter(childRect.center());
    QToolTip::showText(mapToGlobal(rect.topLeft()), text, this);
}

QPushButton *DispatchWidget::newButton()
{
    auto newItem = new QPushButton();
    newItem->setFlat(true);
    newItem->setText("+");
    newItem->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    connect(newItem, &QAbstractButton::clicked, this, &DispatchWidget::slot_video_button_clicked);
    newItem->setAcceptDrops(true);
    newItem->installEventFilter(this);
    return newItem;
}
